// ----------------------------------------------------------
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v.2.0. If a copy of the MPL
// was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
// ----------------------------------------------------------
// Codebase: https://github.com/ArKuznetsov/cpdb/
// ----------------------------------------------------------

#Использовать v8runner
#Использовать v8storage
#Использовать ParserFileV8i
#Использовать fs

Перем Лог;           // - Объект    - объект записи лога приложения

#Область ПрограммныйИнтерфейс

// Выполняет выгрузку информационной базы в DT-файл
//
// Параметры:
//   ПараметрыИБ                    - Структура    - параметры подключения к базе 1С
//      * СтрокаПодключения           - Строка       - строка подключения к базе 1С
//      * Пользователь                - Строка       - имя пользователя базы 1С
//      * Пароль                      - Строка       - пароль пользователя базы 1С
//   ПутьКФайлу                     - Строка       - путь к DT-файлу для выгрузки базы 1С
//   ИспользуемаяВерсияПлатформы    - Строка       - маска версии 1С
//   КлючРазрешения                 - Строка       - ключ разрешения входа в заблоrированную серверную базу 1С (/UC)
//
Процедура ВыгрузитьИнформационнуюБазуВФайл(Знач ПараметрыИБ,
                                           Знач ПутьКФайлу,
                                           Знач ИспользуемаяВерсияПлатформы,
                                           Знач КлючРазрешения = "") Экспорт

	ПутьКФайлу = ФС.ПолныйПуть(ПутьКФайлу);

	Конфигуратор = НастроитьКонфигуратор(ПараметрыИБ.СтрокаПодключения,
	                                     ПараметрыИБ.Пользователь,
	                                     ПараметрыИБ.Пароль,
	                                     ИспользуемаяВерсияПлатформы);
	
	Если НЕ ПустаяСтрока(КлючРазрешения) Тогда
		Конфигуратор.УстановитьКлючРазрешенияЗапуска(КлючРазрешения);
	КонецЕсли;

	Лог.Информация("Начало выгрузки информационной базы %1 в файл %2.",
	               ПараметрыИБ.СтрокаПодключения,
	               ПутьКФайлу);

	Попытка
		Конфигуратор.ВыгрузитьИнформационнуюБазу(ПутьКФайлу);

		Лог.Информация("Информационная база %1 выгружена в файл %2.",
		               ПараметрыИБ.СтрокаПодключения,
		               ПутьКФайлу);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка выгрузки базы %1 в файл %2: %3%4",
		                        ПараметрыИБ.СтрокаПодключения,
		                        ПутьКФайлу,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

КонецПроцедуры // ВыгрузитьИнформационнуюБазуВФайл()

// Выполняет загрузку информационной базы из DT-файла
//
// Параметры:
//   ПараметрыИБ                    - Строка    - параметры подключения к базе 1С
//      * СтрокаПодключения           - Строка    - строка подключения к базе 1С
//      * Пользователь                - Строка    - имя пользователя базы 1С
//      * Пароль                      - Строка    - пароль пользователя базы 1С
//   ПутьКФайлу                     - Строка    - путь к DT-файлу для загрузки в базу 1С
//   КоличествоЗаданий              - Число     - количество заданий загрузки DT-файла для клиент-серверной базы
//   ИспользуемаяВерсияПлатформы    - Строка    - маска версии 1С
//   КлючРазрешения                 - Строка    - ключ разрешения входа в заблоrированную серверную базу 1С (/UC)
//
Процедура ЗагрузитьИнформационнуюБазуИзФайла(Знач ПараметрыИБ,
                                             Знач ПутьКФайлу,
                                             Знач КоличествоЗаданий = 0,
                                             Знач ИспользуемаяВерсияПлатформы = "8.3",
                                             Знач КлючРазрешения = "") Экспорт

	ПутьКФайлу = ФС.ПолныйПуть(ПутьКФайлу);
	
	Конфигуратор = НастроитьКонфигуратор(ПараметрыИБ.СтрокаПодключения,
	                                     ПараметрыИБ.Пользователь,
	                                     ПараметрыИБ.Пароль,
	                                     ИспользуемаяВерсияПлатформы);

	Если НЕ ПустаяСтрока(КлючРазрешения) Тогда
		Конфигуратор.УстановитьКлючРазрешенияЗапуска(КлючРазрешения);
	КонецЕсли;

	Лог.Информация("Начало загрузки информационной базы %1 из файла %2.",
	               ПараметрыИБ.СтрокаПодключения,
	               ПутьКФайлу);

	Попытка
		Конфигуратор.ЗагрузитьИнформационнуюБазу(ПутьКФайлу,
		                                         КоличествоЗаданий);

		Лог.Информация("Информационная база %1 загружена из файла %2.",
		               ПараметрыИБ.СтрокаПодключения,
		               ПутьКФайлу);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка загрузки базы %1 из файла %2: %3%4",
		                        ПараметрыИБ.СтрокаПодключения,
		                        ПутьКФайлу,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

КонецПроцедуры // ЗагрузитьИнформационнуюБазуИзФайла()

// Выполняет очистку локального кэша информационной базы 1С
//
// Параметры:
//   СтрокаПодключения           - Строка    - строка подключения к базе 1С
//
Процедура ОчиститьЛокальныйКэшИнформационнойБазы(Знач СтрокаПодключения) Экспорт

	ДлинаТипаПодключения = 2;
	ТипПодключения = Лев(ВРег(СтрокаПодключения), ДлинаТипаПодключения);
	АдресПодключения = СокрЛП(Сред(СтрокаПодключения, ДлинаТипаПодключения + 1));

	Если ТипПодключения = "/F" Тогда
		ПутьКБазе = АдресПодключения;
	ИначеЕсли ТипПодключения = "/S" Тогда
		ПутьКБазе = АдресПодключения;
		ПутьКБазе = СтрЗаменить(ПутьКБазе, "\", ":");
	Иначе
		ПутьКБазе = СтрокаПодключения;
	КонецЕсли;

	ПарсерСпискаБаз = Новый ПарсерСпискаБаз();
	ПарсерСпискаБаз.УстановитьФайл();

	Результат = ПарсерСпискаБаз.НайтиПоПути(ПутьКБазе);
	Если Результат = Неопределено Тогда
		Лог.Предупреждение("Ошибка очистки кэша, база %1 не найдена в списке баз.", ПутьКБазе);
	Иначе
		Чистильщик = Новый ОчисткаКеша();
		Чистильщик.УстановитьПарсер(ПарсерСпискаБаз);
		Чистильщик.ОчиститьКеш(Результат);

		Лог.Информация("Выполнена очистка кэша базы ""%1"".", СтрокаПодключения);
	КонецЕсли;

КонецПроцедуры // ОчиститьЛокальныйКэшИнформационнойБазы()

// Выполняет очистку всех локальных кэшей информационных баз 1С
//
Процедура ОчиститьВсеЛокальныеКэшиИнформационныхБаз() Экспорт

	КаталогКэша = ПолучитьКаталогКэша();

	КаталогиКэша = НайтиФайлы(КаталогКэша, "*");

	РВ = Новый РегулярноеВыражение("(?i)[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");

	Для Каждого ТекКаталог Из КаталогиКэша Цикл

		Если НЕ ТекКаталог.ЭтоКаталог() Тогда
			Продолжить;
		КонецЕсли;
	
		Если НЕ РВ.Совпадает(ТекКаталог.Имя) Тогда
			Продолжить;
		КонецЕсли;

		Попытка
			УдалитьФайлы(ТекКаталог.ПолноеИмя);
			Лог.Информация("Удален каталог кэша ""%1"".", ТекКаталог.ПолноеИмя);
		Исключение
			ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			Лог.Предупреждение("Ошибка удаления каталога кэша ""%1"": %2%3",
			                   ТекКаталог.ПолноеИмя,
			                   Символы.ПС,
			                   ТекстОшибки);
		КонецПопытки;
		
	КонецЦикла;

КонецПроцедуры // ОчиститьВсеЛокальныеКэшиИнформационныхБаз()

// Выполняет отключение информационной базы от хранилища конфигурации
//
// Параметры:
//   ПараметрыИБ                    - Строка    - параметры подключения к базе 1С
//      * СтрокаПодключения           - Строка    - строка подключения к базе 1С
//      * Пользователь                - Строка    - имя пользователя базы 1С
//      * Пароль                      - Строка    - пароль пользователя базы 1С
//   ИспользуемаяВерсияПлатформы    - Строка    - маска версии 1С
//   ИмяРасширения                  - Строка    - имя расширения, отключаемого от хранилища
//                                                (если не указано, отключается основная конфигурация)
//   КлючРазрешения                 - Строка    - ключь разрешения входа в заблоrированную серверную базу 1С (/UC)
//
Процедура ОтключитьОтХранилища(ПараметрыИБ,
                               Знач ИспользуемаяВерсияПлатформы,
                               Знач ИмяРасширения = "",
                               Знач КлючРазрешения = "") Экспорт

	Конфигуратор = НастроитьКонфигуратор(ПараметрыИБ.СтрокаПодключения,
                                         ПараметрыИБ.Пользователь,
                                         ПараметрыИБ.Пароль,
                                         ИспользуемаяВерсияПлатформы);

	Если НЕ ПустаяСтрока(КлючРазрешения) Тогда
		Конфигуратор.УстановитьКлючРазрешенияЗапуска(КлючРазрешения);
	КонецЕсли;

	МенеджерХранилища = Новый МенеджерХранилищаКонфигурации(, Конфигуратор);

	Если ЗначениеЗаполнено(ИмяРасширения) Тогда
		МенеджерХранилища.УстановитьРасширениеХранилища(ИмяРасширения);
		ТекстОписанияБазы = СтрШаблон("расширения ""%1"" информационной базы ""%2""",
		                              ИмяРасширения,
		                              ПараметрыИБ.СтрокаПодключения);
	Иначе
		ТекстОписанияБазы = СтрШаблон("информационной базы ""%1""", ПараметрыИБ.СтрокаПодключения);
	КонецЕсли;

	Лог.Информация("Начало отключения %1 от хранилища.",
	               ТекстОписанияБазы);
	
	Попытка
		МенеджерХранилища.ОтключитьсяОтХранилища();

		Лог.Информация("Выполнено отключение %1 от хранилища.",
		               ТекстОписанияБазы);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка отключения %1 от хранилища: %2%3",
		                        ТекстОписанияБазы,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

КонецПроцедуры // ОтключитьОтХранилища()

// Выполняет подключение информационной базы к хранилищу конфигурации
//
// Параметры:
//   ПараметрыИБ                    - Структура    - параметры подключения к базе 1С
//      * СтрокаПодключения           - Строка       - строка подключения к базе 1С
//      * Пользователь                - Строка       - имя пользователя базы 1С
//      * Пароль                      - Строка       - пароль пользователя базы 1С
//   ПараметрыХранилища             - Структура    - параметры подключения к хранилищу конфигурации
//      * Адрес                       - Строка       - адрес хранилища конфигурации
//      * Пользователь                - Строка       - имя пользователя хранилища конфигурации
//      * Пароль                      - Строка       - пароль пользователя хранилища конфигурации
//   ИспользуемаяВерсияПлатформы    - Строка       - маска версии 1С
//   ИмяРасширения                  - Строка       - имя расширения, отключаемого от хранилища
//                                                   (если не указано, отключается основная конфигурация)
//   ОбновитьИБ                     - Булево       - Истина - после обновления обновить конфигурацию базы данных
//   КлючРазрешения                 - Строка       - ключь разрешения входа в заблоrированную серверную базу 1С (/UC)
//
Процедура ПодключитьКХранилищу(Знач ПараметрыИБ,
                               Знач ПараметрыХранилища,
                               Знач ИспользуемаяВерсияПлатформы,
                               Знач ИмяРасширения = "",
                               Знач ОбновитьИБ = Ложь,
                               Знач КлючРазрешения = "") Экспорт

	Конфигуратор = НастроитьКонфигуратор(ПараметрыИБ.СтрокаПодключения,
	                                     ПараметрыИБ.Пользователь,
	                                     ПараметрыИБ.Пароль,
	                                     ИспользуемаяВерсияПлатформы);
	
	Если Не ПустаяСтрока(КлючРазрешения) Тогда
		Конфигуратор.УстановитьКлючРазрешенияЗапуска(КлючРазрешения);
	КонецЕсли;

	МенеджерХранилища = Новый МенеджерХранилищаКонфигурации(ПараметрыХранилища.Адрес, Конфигуратор);
	
	Если ЗначениеЗаполнено(ПараметрыХранилища.Пользователь) Тогда
		МенеджерХранилища.УстановитьПараметрыАвторизации(ПараметрыХранилища.Пользователь, ПараметрыХранилища.Пароль);
	КонецЕсли;

	Если ЗначениеЗаполнено(ИмяРасширения) Тогда
		МенеджерХранилища.УстановитьРасширениеХранилища(ИмяРасширения);
		ТекстОписанияБазы = СтрШаблон("расширения ""%1"" информационной базы ""%2""",
		                              ИмяРасширения,
		                              ПараметрыИБ.СтрокаПодключения);
	Иначе
		ТекстОписанияБазы = СтрШаблон("информационной базы ""%1""", ПараметрыИБ.СтрокаПодключения);
	КонецЕсли;

	Лог.Информация("Начало подключения %1 к хранилищу %2.",
	               ТекстОписанияБазы,
	               ПараметрыХранилища.Адрес);

	Попытка
		МенеджерХранилища.ПодключитьсяКХранилищу(Истина);

		// Иногда проявляется проблема, что при подключении
		// выполняется получение не последней версии конфигурации.
		// Для контроля получаем конфигурацию из хранилища.
		МенеджерХранилища.ОбновитьКонфигурациюНаВерсию();

		Если ОбновитьИБ Тогда
			Конфигуратор.ОбновитьКонфигурациюБазыДанных();
		КонецЕсли;

		Лог.Информация("Выполнено подключение %1 к хранилищу %2.",
		               ТекстОписанияБазы,
		               ПараметрыХранилища.Адрес);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка подключения %1 к хранилищу %2: %3%4",
		                        ТекстОписанияБазы,
		                        ПараметрыХранилища.Адрес,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

КонецПроцедуры // ПодключитьКХранилищу()

// Создание серверной информационной базы 1С
//
// Параметры:
//  Параметры1С                 - Структура
//     * Сервер1С                 - Строка     - Адрес кластера серверов 1С ([<протокол>://]<адрес>[:<порт>])
//     * ИмяИБ                    - Строка     - Имя информационной базы на сервере 1С
//     * РазрешитьВыдачуЛицензий  - Булево     - Истина - разрешить выдачу лицензий сервером 1С (по умолчанию: Истина)
//     * РазрешитьРегЗадания      - Булево     - Истина - разрешить запуск рег. заданий (по умолчанию: Ложь)
//  ПараметрыСУБД               - Структура
//     * ТипСУБД                  - Строка     - Тип сервера СУБД ("MSSQLServer" <по умолчанию>,
//                                               "PostgreSQL", "IBMDB2", "OracleDatabase")
//     * СерверСУБД               - Строка     - Адрес сервера СУБД
//     * ПользовательСУБД         - Строка     - Пользователь сервера СУБД
//     * ПарольСУБД               - Строка     - Пароль пользователя сервера СУБД
//     * ИмяБД                    - Строка     - Имя базы на сервере СУБД (если не указано будет использовано имя ИБ 1С)
//     * СмещениеДат              - Строка     - Смещение дат на сервере MS SQL (0; 2000 <по умолчанию>)
//     * СоздаватьБД              - Булево     - Истина - будет создана база на сервере СУБД в случае отсутствия
//                                               (по умолчанию: Ложь)
//  АвторизацияВКластере        - Структура
//     * Имя                      - Строка     - Имя администратора кластера 1С
//     * Пароль                   - Строка     - Пароль администратора кластера 1С
//  ИспользуемаяВерсияПлатформы - Строка       - маска версии 1С
//  ОшибкаЕслиСуществует        - Булево     - Истина - Вызвать исключение если ИБ в кластере 1С существует
//                                             (по умолчанию: Ложь)
//  ПутьКШаблону                - Строка     - Путь к шаблону для создания информационной базы (*.cf; *.dt).
//                                             Если шаблон не указан, то будет создана пустая ИБ
//  ИмяВСпискеБаз 	            - Строка     - Имя в списке баз пользователя
//                                             (если не задано, то ИБ в список не добавляется)
//
Процедура СоздатьСервернуюБазу(Знач Параметры1С,
                               Знач ПараметрыСУБД,
                               Знач АвторизацияВКластере,
                               Знач ИспользуемаяВерсияПлатформы = "",
                               Знач ОшибкаЕслиСуществует = Ложь,
                               Знач ПутьКШаблону = "",
                               Знач ИмяВСпискеБаз = "") Экспорт

	ПутьКШаблону = ФС.ПолныйПуть(ПутьКШаблону);
	
	Конфигуратор = Новый УправлениеКонфигуратором();
	Конфигуратор.ИспользоватьВерсиюПлатформы(ИспользуемаяВерсияПлатформы);
	
	Лог.Информация("Начало создания базы ""%1"" на сервере ""%2""",
	               Параметры1С.ИмяИБ,
	               Параметры1С.Сервер1С);
	Попытка
		Конфигуратор.СоздатьСервернуюБазу(Параметры1С,
		                                  ПараметрыСУБД,
		                                  АвторизацияВКластере,
		                                  ОшибкаЕслиСуществует,
		                                  ПутьКШаблону,
		                                  ИмяВСпискеБаз);

		Лог.Информация("Выполнено создание базы ""%1"" на сервере ""%2""",
		               Параметры1С.ИмяИБ,
		               Параметры1С.Сервер1С);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка создания базы ""%1"" на сервере ""%2"": %3%4",
		                        Параметры1С.ИмяИБ,
		                        Параметры1С.Сервер1С,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

КонецПроцедуры // СоздатьСервернуюБазу()

// Создание файловой информационной базы 1С
//
// Параметры:
//  ПутьКБазе                   - Строка    - путь к каталогу базы 1С
//  ИспользуемаяВерсияПлатформы - Строка    - маска версии 1С
//  ОшибкаЕслиСуществует        - Булево    - Истина - Вызвать исключение если ИБ в кластере 1С существует
//                                            (по умолчанию: Ложь)
//  ПутьКШаблону                - Строка    - Путь к шаблону для создания информационной базы (*.cf; *.dt).
//                                            Если шаблон не указан, то будет создана пустая ИБ
//  ИмяВСпискеБаз 	            - Строка    - Имя в списке баз пользователя
//                                            (если не задано, то ИБ в список не добавляется)
//
Процедура СоздатьФайловуюБазу(Знач ПутьКБазе,
                              Знач ИспользуемаяВерсияПлатформы = "",
                              Знач ОшибкаЕслиСуществует = Ложь,
                              Знач ПутьКШаблону = "",
                              Знач ИмяВСпискеБаз = "") Экспорт

	ПутьКБазе = ФС.ПолныйПуть(ПутьКБазе);
	
	ПутьКШаблону = ФС.ПолныйПуть(ПутьКШаблону);
	
	Конфигуратор = Новый УправлениеКонфигуратором();
	Конфигуратор.ИспользоватьВерсиюПлатформы(ИспользуемаяВерсияПлатформы);
	
	Лог.Информация("Начало создания базы в каталоге ""%1""", ПутьКБазе);

	Если ОшибкаЕслиСуществует Тогда
		ФайлБазы = Новый Файл(ОбъединитьПути(ПутьКБазе, "1Cv8.1CD"));
		Если ФайлБазы.Существует() Тогда
			ТекстОшибки = СтрШаблон("В каталоге ""%1"" уже существует база 1С", ПутьКБазе);
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
	КонецЕсли;

	Попытка
		Конфигуратор.СоздатьФайловуюБазу(ПутьКБазе, ПутьКШаблону, ИмяВСпискеБаз);

		Лог.Информация("Выполнено создание базы в каталоге ""%1""", ПутьКБазе);
	Исключение
		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка создания базы в каталоге ""%1"": %2%3",
		                        ПутьКБазе,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

КонецПроцедуры // СоздатьФайловуюБазу()

#КонецОбласти // ПрограммныйИнтерфейс

#Область СлужебныеПроцедурыИФункции

// Функция подготавливает конфигуратор 1С для выполнения в режиме командной строки
//
// Параметры:
//   СтрокаПодключения              - Строка    - строка подключения к базе 1С
//   ИмяПользователя                - Строка    - имя пользователя базы 1С
//   ПарольПользователя             - Строка    - пароль пользователя базы 1С
//   ИспользуемаяВерсияПлатформы    - Строка    - маска версии 1С
//
// Возвращаемое значение:
//   Строка    - Обработанная строка
//
Функция НастроитьКонфигуратор(СтрокаПодключения,
                              ИмяПользователя = Неопределено,
                              ПарольПользователя = Неопределено,
                              ИспользуемаяВерсияПлатформы = Неопределено)
	
	Конфигуратор = Новый УправлениеКонфигуратором;

	КаталогСборки = КаталогВременныхФайлов();

	Конфигуратор.КаталогСборки(КаталогСборки);

	Если ЗначениеЗаполнено(СтрокаПодключения) Тогда
		Конфигуратор.УстановитьКонтекст(СтрокаПодключения, ИмяПользователя, ПарольПользователя);
	КонецЕсли;

	Если НЕ ИспользуемаяВерсияПлатформы = Неопределено Тогда
		Конфигуратор.ИспользоватьВерсиюПлатформы(ИспользуемаяВерсияПлатформы);
	КонецЕсли;

	Возврат Конфигуратор;

КонецФункции // НастроитьКонфигуратор()

// Получить каталог кеша информационных баз 1С
// с учетом операционной системы
//
// Возвращаемое значение:
//   Строка    - путь к каталогу кэша ИБ 1С
//
Функция ПолучитьКаталогКэша()
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	ЭтоWindows = Найти(ВРег(СистемнаяИнформация.ВерсияОС), "WINDOWS") > 0;
	Если ЭтоWindows Тогда
		ЗначениеПеременной = ПолучитьПеременнуюСреды("USERPROFILE");
		КаталогКеша = ОбъединитьПути(ЗначениеПеременной, "appdata\local\1c\1cv8");
	Иначе
		ЗначениеПеременной = ПолучитьПеременнуюСреды("HOME");
		КаталогКеша = ОбъединитьПути(ЗначениеПеременной, "./.1cv82/1C/1Cv82/");
	КонецЕсли;

	Возврат КаталогКеша;

КонецФункции // ПолучитьКаталогКэша()

#КонецОбласти // СлужебныеПроцедурыИФункции

Лог = ПараметрыСистемы.Лог();
